package com.googlecode.saucelabs;

import org.apache.http.HttpMessage;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.logging.Log;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Logger;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;

public abstract class AbstractSauceMojo extends AbstractMojo {
	public class MojoLogger implements Logger {
		private Log logger = getLog();

		@Override
		public boolean isEnabled(int level) {
			if (level == Logger.DEBUG) {
				return logger.isDebugEnabled();
			} else if (level == Logger.ERROR) {
				return logger.isErrorEnabled();
			} else if (level == Logger.FATAL) {
				return logger.isErrorEnabled();
			} else if (level == Logger.INFO) {
				return logger.isInfoEnabled();
			} else if (level == Logger.WARN) {
				return logger.isWarnEnabled();
			}

			return false;
		}

		@Override
		public void log(int level, String message) {
			if (level == Logger.DEBUG) {
				logger.debug(message);
			} else if (level == Logger.ERROR) {
				logger.error(message);
			} else if (level == Logger.FATAL) {
				logger.error(message);
			} else if (level == Logger.INFO) {
				logger.info(message);
			} else if (level == Logger.WARN) {
				logger.warn(message);
			}
		}
	}

	public static final String TUNNEL_SESSION = AbstractSauceMojo.class
			.getName()
			+ ".TUNNEL_SESSION";

	/**
	 * @parameter default-value="${sauceLabsUser}"
	 */
	String username;

	/**
	 * @parameter default-value="${sauceLabsKey}"
	 */
	String userKey;

	/**
	 * @parameter default-value="${sauceDomains}"
	 */
	String[] domains;

	private HttpClient httpClient;

	public AbstractSauceMojo() {
		super();
	}

	Session getJSch(String user, String host) throws Exception {
		JSch jsch = new JSch();

		return jsch.getSession(user, host, 22);
	}

	HttpClient getHttpClient() {
		if (null == httpClient) {
			DefaultHttpClient _httpClient = new DefaultHttpClient();

			_httpClient.getCredentialsProvider().setCredentials(
					new AuthScope("saucelabs.com", AuthScope.ANY_PORT),
					new UsernamePasswordCredentials(username, userKey));

			httpClient = _httpClient;
		}

		return httpClient;
	}

	@SuppressWarnings("unchecked")
	protected <T extends HttpMessage> T getRequest(Class<T> messageClass,
			String path, String... args) {
		String requestUrl = String.format("https://saucelabs.com" + path,
				(Object[]) args);
		HttpMessage httpMessage = null;

		if (messageClass.equals(HttpPost.class)) {
			httpMessage = new HttpPost(requestUrl);
		} else if (messageClass.equals(HttpGet.class)) {
			httpMessage = new HttpGet(requestUrl);
		}

		httpMessage.setHeader("Content-Type", "application/json");

		return (T) httpMessage;
	}

	protected void logMessage(String pattern, Object... args) {
		Log logger = getLog();

		if (logger.isInfoEnabled()) {
			logger.info(String.format(pattern, (Object[]) args));
		}
	}

	@SuppressWarnings("unchecked")
	protected void setSession(Session session) {
		getPluginContext().put(TUNNEL_SESSION, session);
	}

	protected Session getSession() {
		return (Session) getPluginContext().get(TUNNEL_SESSION);
	}

	abstract class AbstractSauceCommand<T> {
		private HttpUriRequest httpUriRequest;

		public AbstractSauceCommand(HttpUriRequest httpUriRequest) {
			this.httpUriRequest = httpUriRequest;
		}

		public void onSetupConnection(HttpUriRequest httpUriRequest)
				throws Exception {
		}

		public abstract T onEntityResult(HttpResponse httpResult,
				String entityResult) throws Exception;

		public T execute() throws Exception {
			onSetupConnection(httpUriRequest);

			logMessage("Request to %s", httpUriRequest.getURI().toString());

			HttpResponse httpResult = getHttpClient().execute(httpUriRequest);

			String entityResultAsString = EntityUtils.toString(httpResult
					.getEntity());

			logMessage("Response: %s", entityResultAsString);

			return onEntityResult(httpResult, entityResultAsString);
		}
	}

	class JSchAuthInfo implements UserInfo {
		public void showMessage(String arg0) {
		}

		public boolean promptYesNo(String arg0) {
			return false;
		}

		public boolean promptPassword(String arg0) {
			return true;
		}

		public boolean promptPassphrase(String arg0) {
			return false;
		}

		public String getPassword() {
			return userKey;
		}

		public String getPassphrase() {
			return null;
		}
	}
}
